home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
visulztn
/
saoimage
/
saoimage.lha
/
sclmap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-20
|
9KB
|
293 lines
#ifndef lint
static char SccsId[] = "%W% %G%";
#endif
/* Module: sclmap.c (Scale Map)
* Purpose: Map image values to display screen values using various
* functions
* Subroutine: make_scalemap() returns: void
* Copyright: 1989 Smithsonian Astrophysical Observatory
* You may do anything you like with this file except remove
* this copyright. The Smithsonian Astrophysical Observatory
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
* Modified: {0} Michael VanHilst initial version 26 May 1989
* {n} <who> -- <does what> -- <when>
*/
#include <stdio.h> /* get stderr, NULL, etc. */
#include <math.h> /* get the math definitions */
#include <X11/Xlib.h> /* X window stuff */
#include <X11/Xutil.h> /* X window manager stuff */
#include "hfiles/constant.h" /* define codes */
#include "hfiles/struct.h" /* declare structure types */
#include "hfiles/extern.h" /* extern main parameter structures */
#include "hfiles/scale.h" /* define scaling constants */
#ifndef SUN
#define expm1(a) (exp(a)-1)
#endif
/*
* Subroutine: make_scalemap
* Purpose: Make scale map according to type selected
* Note: Map goes from image value to hardware value (through ideal
* map value using pixels array from XAllocColors)
*/
void make_scalemap ( image_min, image_max )
int image_min, image_max; /* i: range of mapping for image data input */
{
void histogram_equalize();
static void linear_scale(), wrap_scale(), sqrt_scale(), log_scale();
/* note the range of data for which mapping is to be calculated */
if( image_max == image_min )
++image_max;
if( image_max < image_min ) {
int temp;
temp = image_max;
image_max = image_min;
image_min = temp;
}
{
/* fill in map below min with mincolor */
register int imageval;
register int pixval;
register unsigned char *lookup; /* l: scalemap base (signed index) */
lookup = buffer.scalemap + SCALEOFF;
pixval = color.pixvalmap[0];
for( imageval = -32768; imageval < image_min; imageval++ )
lookup[imageval] = pixval;
}
/* create the image map straight or with some form of scaling */
switch( color.scale.mode ) {
case SOP_HistEq:
/* if there are levels to distribute, call the routine, else do the next */
if( color.ncolors < (image_max - image_min) ) {
histogram_equalize(buffer.scalemap + SCALEOFF,
buffer.histogram + SCALEOFF, buffer.hist_area,
image_min, image_max,
color.ncolors, color.pixvalmap);
break;
}
/* fall through to linear if there is nothing to distribute */
case SOP_Linear:
linear_scale(image_min, image_max);
break;
case SOP_Wrap:
wrap_scale(image_min, image_max);
/* don't fill in the top of map */
return;
case SOP_Sqrt:
sqrt_scale(image_min, image_max);
break;
case SOP_Log:
log_scale(image_min, image_max);
break;
default:
(void)fprintf(stderr,"Unknown scaling type request!\n");
}
{
/* fill in top of map with maxcolor */
register int imageval;
register int pixval;
register unsigned char *lookup; /* l: scalemap base (signed index) */
lookup = buffer.scalemap + SCALEOFF;
pixval = color.pixvalmap[color.ncolors - 1];
for( imageval = image_max; imageval < 32768; imageval++ )
lookup[imageval] = pixval;
}
}
/*
* Subroutine: linear_scale
* Purpose: Distribute color levels in the map evenly
*/
static void linear_scale ( image_min, image_max )
int image_min, image_max; /* i: limits of values in display */
{
double scale;
double upper_bound;
int maxcolor;
int level;
unsigned long *pixels; /* l: ideal byte to hardare byte map */
register unsigned char *lookup; /* l: scalemap base (signed offsets) */
register int imageval;
register int pixval;
register int imagelim;
lookup = buffer.scalemap + SCALEOFF;
maxcolor = color.ncolors - 1;
pixels = color.pixvalmap;
/* input range / output range yields input cells per ouput cell */
scale = (double)(image_max - image_min + 1) / (double)color.ncolors;
imageval = image_min;
/* upper bound is ideal edge between colors (offset for rounding) */
upper_bound = image_min + 0.5;
level = 0;
pixval = pixels[0];
while( level++ < maxcolor ) {
upper_bound += scale;
imagelim = (int)upper_bound;
while( imageval < imagelim )
lookup[imageval++] = pixval;
/* level was inc'd after loop test, make pixval for next round */
pixval = pixels[level];
}
/* fill in at top if short of image_max */
while( imageval <= image_max )
lookup[imageval++] = pixval;
}
/*
* Subroutine: wrap_scale
* Purpose: Create the image map with a repeating linear scale
* Note: Levels below image_min are not mapped
*/
static void wrap_scale ( image_min, image_max )
int image_min, image_max; /* i: limits of values in display */
{
double scale;
double range;
int maxcolor;
int level;
unsigned long *pixels; /* l: ideal byte to hardare byte map */
register unsigned char *lookup; /* l: scalemap base (signed offsets) */
register int imageval;
register int pixval;
register int imagelim;
lookup = buffer.scalemap + SCALEOFF;
maxcolor = color.ncolors - 1;
pixels = color.pixvalmap;
/* input range / output range yields input cells per ouput cell */
imagelim = (image_max - image_min + 1) / color.scale.wrap_cnt;
scale = (double)imagelim / (double)color.ncolors;
/* start at image_min with color level = 0 */
imageval = image_min;
level = 0;
/* use range as floating point boundary between levels */
range = (double)imageval;
while( imageval < 32768 ) {
do {
/* level was inc'd after loop test, make pixval for next round */
pixval = pixels[level];
range += scale;
imagelim = (int)(range + 0.5);
if( imagelim >= 32768 )
imagelim = 32767;
do {
lookup[imageval] = pixval;
} while( ++imageval <= imagelim );
if( imageval >= 32768 )
return;
} while( ++level <= maxcolor );
/* pixval at level 0 lowest color again */
level = 0;
}
}
/*
* Subroutine: sqrt_scale
* Purpose: Distribute color levels in the map by a root or power function.
* Method: (level / maxlevel) ranges from 0 to 1. Raise to a power.
* Result curves from 0 to 1. Map result directly back to
* pixel value.
*/
static void sqrt_scale ( image_min, image_max )
int image_min, image_max; /* i: limits of values in display */
{
double range;
double power;
double ncolors;
int maxcolor;
int level;
unsigned long *pixels; /* l: ideal byte to hardare byte map */
register unsigned char *lookup; /* l: scalemap base (signed offsets) */
register int imageval;
register int pixval;
register int imagelim;
lookup = buffer.scalemap + SCALEOFF;
maxcolor = color.ncolors - 1;
pixels = color.pixvalmap;
power = color.scale.root_power;
ncolors = (double)color.ncolors;
range = image_max - image_min + 1;
imageval = image_min;
level = 0;
/* pixval at level 0 is pixoffset (lshifted 0 is still 0) */
pixval = pixels[0];
while( level++ < maxcolor ) {
imagelim = image_min + (int)
((pow(((double)level / ncolors), power) * range) + 0.5);
/* limit map range to image values */
if( imagelim > image_max )
imagelim = image_max;
while( imageval < imagelim )
lookup[imageval++] = pixval;
/* level was inc'd after loop test, make pixval for next round */
pixval = pixels[level];
}
/* fill in at top if short of image_max */
while( imageval <= image_max )
lookup[imageval++] = pixval;
}
/*
* Subroutine: log_scale
* Purpose: Distribute color levels in the map by a logorithmic or
* exponential curve (powers of e).
*/
static void log_scale ( image_min, image_max )
int image_min, image_max; /* i: limits of values in display */
{
double scale;
double expo;
double ncolors;
int maxcolor;
int level;
unsigned long *pixels; /* l: ideal byte to hardare byte map */
register unsigned char *lookup; /* l: scalemap base (signed offsets) */
register int imageval;
register int pixval;
register int imagelim;
lookup = buffer.scalemap + SCALEOFF;
maxcolor = color.ncolors - 1;
pixels = color.pixvalmap;
expo = color.scale.log_expo;
ncolors = (double)color.ncolors;
/* base distribution on e**n as n goes from 0 to expo (expm1 is exp()-1) */
if( color.scale.log_expo >= 0 ) {
scale = (double)(image_max - image_min + 1) / expm1(expo);
} else {
/* negative exponents allocate more levels toward the high values */
scale = (double)(image_max - image_min + 1) / (1.0 - exp(expo));
}
imageval = image_min;
level = 0;
/* pixval at level 0 is pixoffset (lshifted 0 is still 0) */
pixval = pixels[0];
while( level++ < maxcolor ) {
if( expo > 0 ) {
imagelim = image_min + (int)
((expm1(((double)level / ncolors) * expo) * scale) + 0.5);
} else {
imagelim = image_min + (int)
((1.0-exp(((double)level / ncolors) * expo) * scale) + 0.5);
}
/* limit map range to image values */
if( imagelim > image_max )
imagelim = image_max;
while( imageval < imagelim )
lookup[imageval++] = pixval;
/* level was inc'd after loop test, make pixval for next round */
pixval = pixels[level];
}
/* fill in at top if short of image_max */
while( imageval <= image_max )
lookup[imageval++] = pixval;
}